namespace SPDeploy.Library.Processing.Library
{
    using System.Collections.Generic;
    using System.Linq;
    using System.Reflection;
    using Interfaces;

    public class ProcessorSettingsManager
    {
        #region Fields: private

        private readonly IDeploymentTargetProcessor _target;

        #endregion

        public ProcessorSettingsManager(IDeploymentTargetProcessor target)
        {
            _target = target;
            InitializeDefaultValues();
        }

        #region Properties: public

        public IEnumerable<string> ConfigKeys
        {
            get
            {
                foreach (PropertyInfo property in ConfigProperties)
                {
                    yield return property.Name;
                }
            }
        }

        public string ConfigName
        {
            get { return _target.Name; }
        }

        #endregion

        #region Properties: private

        private PropertyInfo[] ConfigProperties
        {
            get
            {
                return (from property in _target.GetType().GetProperties(BindingFlags.Public | BindingFlags.Instance | BindingFlags.SetProperty)
                        where IsProcessorSetting(property)
                        select property).ToArray();
            }
        }

        #endregion

        #region Methods: public

        public string GetConfigValue(string configKey)
        {
            PropertyInfo property = _target.GetType().GetProperty(configKey, BindingFlags.Public | BindingFlags.Instance | BindingFlags.SetProperty);
            object value = property.GetValue(_target, null);
            if (value == null)
            {
                return "";
            }
            return property.GetValue(_target, null).ToString();
        }

        public bool SetConfigValue(string configKey, object value)
        {
            PropertyInfo property = _target.GetType().GetProperty(configKey, BindingFlags.Public | BindingFlags.Instance | BindingFlags.SetProperty);
            if (property != null &&
                IsProcessorSetting(property))
            {
                property.SetValue(_target, value, null);
                return true;
            }
            return false;
        }

        #endregion

        #region Methods: private

        private static ProcessorSettingAttribute GetProcessorSettingAttribute(ICustomAttributeProvider property)
        {
            var attributes = property.GetCustomAttributes(typeof (ProcessorSettingAttribute), true) as ProcessorSettingAttribute[];
            if (attributes == null || attributes.Length == 0)
            {
                return null;
            }
            return attributes[0];
        }

        private void InitializeDefaultValues()
        {
            foreach (PropertyInfo property in ConfigProperties)
            {
                ProcessorSettingAttribute processorSettingAttribute = GetProcessorSettingAttribute(property);
                if (processorSettingAttribute != null)
                {
                    property.SetValue(_target, processorSettingAttribute.DefaultValue, null);
                }
            }
        }

        private static bool IsProcessorSetting(ICustomAttributeProvider property)
        {
            return GetProcessorSettingAttribute(property) != null;
        }

        #endregion
    }
}